package org.sothis.core.searcher.impl;

import java.sql.SQLException;
import java.util.List;

import org.hibernate.HibernateException;
import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.transform.CustomAliasToBeanResultTransformer;
import org.sothis.core.searcher.ParameterBean;
import org.sothis.core.searcher.SearcherAgent;
import org.springframework.orm.hibernate3.HibernateCallback;
import org.springframework.orm.hibernate3.HibernateTemplate;

public class HibernateSearcherAgent<E, P extends ParameterBean> extends
    HibernateTemplate implements SearcherAgent<E, P, String>
{
    private Class<E> resultClass = null;

    public int count(final String countStatement,
        final ParameterBean parameterBean)
    {
        return ((Number)execute(new HibernateCallback()
        {
            public Object doInHibernate(Session session)
                throws HibernateException, SQLException
            {
                Query query = session.createQuery(countStatement);
                prepareQuery(query);
                for (String key:parameterBean.getParamMap().keySet())
                {
                    query.setParameter(key, parameterBean.getParamMap()
                        .get(key));
                }
                return query.iterate().next();
            }
        })).intValue();
    }

    @SuppressWarnings("unchecked")
    public List<E> list(final String listStatement,
        final ParameterBean parameterBean, final int firstResult,
        final int maxResults)
    {
        return (List<E>)execute(new HibernateCallback()
        {
            public Object doInHibernate(Session session)
                throws HibernateException, SQLException
            {
                Query query;

                if (null==resultClass)
                {
                    query = session.createQuery(null==parameterBean
                        .getListStatement()?listStatement:parameterBean
                        .getListStatement());
                }
                else
                {
                    query = session
                        .createQuery(
                            null==parameterBean.getListStatement()?listStatement
                                :parameterBean.getListStatement())
                        .setResultTransformer(
                            new CustomAliasToBeanResultTransformer(resultClass));
                }

                prepareQuery(query);
                query.setFirstResult(firstResult);
                query.setMaxResults(maxResults);

                for (String key:parameterBean.getParamMap().keySet())
                {
                    query.setParameter(key, parameterBean.getParamMap()
                        .get(key));
                }
                List<E> resultList = query.list();
                return resultList;
            }
        });
    }

    @SuppressWarnings("unchecked")
    public E uniqueResult(final String listStatement,
        final ParameterBean parameterBean)
    {
        return (E)execute(new HibernateCallback()
        {
            public Object doInHibernate(Session session)
                throws HibernateException, SQLException
            {
                Query query;
                if (null==resultClass)
                {
                    query = session.createQuery(null==parameterBean
                        .getListStatement()?listStatement:parameterBean
                        .getListStatement());
                }
                else
                {
                    query = session
                        .createQuery(
                            null==parameterBean.getListStatement()?listStatement
                                :parameterBean.getListStatement())
                        .setResultTransformer(
                            new CustomAliasToBeanResultTransformer(resultClass));
                }
                prepareQuery(query);
                for (String key:parameterBean.getParamMap().keySet())
                {
                    query.setParameter(key, parameterBean.getParamMap()
                        .get(key));
                }
                return query.uniqueResult();
            }
        });
    }

    public void setResultClass(Class<E> resultClass)
    {
        this.resultClass = resultClass;
    }
}
